home *** CD-ROM | disk | FTP | other *** search
- Path: gatorbox_srqa_121.arh.cdc.com!user
- From: whatmuff@cdc.com (Dave Whatmuff)
- Newsgroups: comp.lang.c++,comp.lang.fortran
- Subject: Re: Calling Fortran in C++
- Date: Mon, 15 Jan 1996 12:22:58 -0600
- Organization: Control Data Systems, Inc.
- Message-ID: <whatmuff-1501961222580001@gatorbox_srqa_121.arh.cdc.com>
- References: <4cr87l$794$1@mhafc.production.compuserve.com>
- NNTP-Posting-Host: 129.179.62.121
-
- In article <4cr87l$794$1@mhafc.production.compuserve.com>, Steve Harris
- <100016.2166@CompuServe.COM> wrote:
-
- > Hello,
- > Can anyone provide me with a 'simple' example, with source code
- > and an 'idiots' step guide, on how to call some FORTRAN code from
- > MS VISUAL C++.
- .....snip.....
-
- Hi Steve,
- I'm in the process of porting a Unix engineering graphics application to
- WindowsNT.
- The code is about 100,000 lines long split 50/50 Fortran/C.
-
- Most of last week I spent trying to understand the documentation on the
- subject of mixed language programming, and in the process, wrote a test
- example which covered most of what I required.
-
- My example has a Fortran main, whilst your question suggested that you
- needed a C main, but I do make calls in both directions, so this might be
- useful to you. As far as compilation and link is concerned, I simply
- created .obj files from the C code, using the Visual C++ compiler, and
- then included those files when building the "project" under Fortran
- Powerstation.
-
- For my own interest, and future reference, I wrote a small document
- describing the process, which I include here.
-
- Good luck,
- Dave
-
- Notes on Mixed-language programming in WindowsNT
- ------------------------------------------------
-
- Using Fortran Powerstation 4.0 and Visual C++ 2.0
-
- Basic premise is to leave the same as much of the existing code as
- possible, and write whatever extra stuff is necessary to cross-talk. This
- is because any C code called from Fortran, is also called from C (and
- vice-versa) so any changes to existing code would have ripple effect. In
- other words, if FORTRAN calls a C function also called by C, I prefer to
- change the FORTRAN calls rather that the C called, and the same for C
- calling FORTRAN.
-
- C calling FORTRAN
- -----------------
-
- 1. Use __stdcall parameter in prototype declaration for all FORTRAN
- routines called, to define FORTRAN calling and cleanup protocol.
-
- 2. Names should be uppercase.
-
- 3. All args should be pointers, and any string arguments should be
- followed by an unsigned int giving the length of the string (best if last
- arg, but I understand that string args should always be immediately
- followed by the "hidden" length, even if in middle of arg list).
-
- 4. Structures duplicating named COMMON blocks are pretty much standard but
- struct names should be in uppercase like the COMMON name. Also beware of
- different storage rules - may need -
-
- #pragma pack(2)
- struct {..........} NAME;
- #pragma pack()
-
- to ensure even byte storage.
-
- 5. FORTRAN functions return values as standard -- I haven't tried
- returning a string value, but integer and real functions are OK.
-
- FORTRAN calling C
- -----------------
-
- 1. All args in C functions called from FORTRAN should be pointers. (This
- is the same in Unix, so any C functions called from Fortran already had
- pointer arguments)
-
- 2. Use INTERFACE block in program block which makes the call, to define -
-
- C calling and cleanup protocol
- all arguments as REFERENCE (actually only necessary for strings to
- prevent Fortran adding the "hidden" length argument, but makes rest
- specific)
- ALIAS to allow C function names to remain same
-
- see example program following -
-
- Example FORTRAN source -
- -------------------------
-
- PROGRAM MIXLANG
-
- INTERFACE
- INTEGER FUNCTION CFUNC(I,F,C)
- !MS$ATTRIBUTES C, ALIAS:'_cfunc_' :: CFUNC
- !MS$ATTRIBUTES REFERENCE :: I
- !MS$ATTRIBUTES REFERENCE :: F
- !MS$ATTRIBUTES REFERENCE :: C
- INTEGER I
- REAL F
- CHARACTER*10 C
- END FUNCTION CFUNC
- END INTERFACE
- *
- CHARACTER C*10
- COMMON/MIXCOM/I,F,C
- PRINT *,'Test of mixed language programming'
- PRINT *,'Setting COMMON values'
- I=98
- F=3.14159
- C="TEST text\0"C
- PRINT *,' I=',I,' F=',F,' C=',C
- K=CFUNC(I,F,C)
- PRINT *,'Return value from CFUNC=',K
- STOP
- END
- *
- SUBROUTINE FSUB(I1,F1,C1)
- CHARACTER C1*(*), C*10
- COMMON/MIXCOM/I,F,C
- L=LEN(C1)
- PRINT *,'FSUB argument values'
- PRINT *,' I1=',I1,' F1=',F1,' C1=',C1,' L=',L
- RETURN
- END
- *
- FUNCTION FFUNC(I,F,C)
- CHARACTER C*(*)
- L=LEN(C)
- PRINT *,'FFUNC argument values'
- PRINT *,' I=',I,' F=',F,' C=',C,' L=',L
- FFUNC=F
- RETURN
- END
- *
- FUNCTION IFUNC(I,F,C)
- CHARACTER C*10
- PRINT *,'IFUNC argument values'
- PRINT *,' I=',I,' F=',F,' C=',C
- IFUNC=I
- RETURN
- END
-
- Example C source -
- -------------------
-
- #include <stdio.h>
- #include <string.h>
-
- extern struct {int i; float f; char c[10];} MIXCOM;
- extern void __stdcall FSUB(int*,float*,char*,int);
- extern double __stdcall FFUNC(int*,float*,char*,int);
- extern int __stdcall IFUNC(int*,float*,char*,int);
-
- cfunc_(i2,f2,c2)
- int *i2;
- float *f2;
- char *c2;
- {
- int i3;
- float f3;
- char *c3;
- int len;
-
- i3= *i2;
- f3= *f2;
- c3= c2;
-
- len=strlen(c2)+1;
-
- printf("cfunc arguments - i2=%d f2=%f c2=%s len=%d\n",*i2,*f2,c2,len);
-
- printf("i3=%d\n",i3);
- printf("f3=%f\n",f3);
- printf("c3=%s\n",c3);
-
-
- printf("struct values i=%d f=%f c=%s\n",MIXCOM.i,MIXCOM.f,MIXCOM.c);
-
- fflush(stdout);
-
- FSUB(&i3,&f3,c3,len);
- fflush(stdout);
-
- printf("Return value from ffunc=%f\n",FFUNC(&i3,&f3,c3,len));
- fflush(stdout);
-
- printf("Return value from ifunc=%d\n",IFUNC(&i3,&f3,c3,len));
- fflush(stdout);
-
- return(i3);
-
- }
-
- Program output -
- ------------------
-
- Test of mixed language programming
- Setting COMMON values
- I= 98 F= 3.141590 C=TEST textcfunc arguments - i2=98 f2=3.141590
- c2=TEST text len=10
- i3=98
- f3=3.141590
- c3=TEST text
- struct values i=98 f=3.141590 c=TEST text
-
- FSUB argument values
- I1= 98 F1= 3.141590 C1=TEST text L= 10
- FFUNC argument values
- I= 98 F= 3.141590 C=TEST text L= 10Return value from ffunc=3.141590
-
- IFUNC argument values
- I= 98 F= 3.141590 C=TEST textReturn value from ifunc=98
-
- Return value from CFUNC= 98
- Stop - Program terminated.
-
- Notes -
- -------
-
- A couple of interesting things about this ouput -
- 1. When I ran the program initially (without the fflush statements in the
- C code), I got the output shown above, but when I redirected the output to
- a file to add to this document, the Fortran output came out all together,
- followed by the C output, suggesting that different buffer files are used
- for the two. However, when I added the fflush statements, the redirected
- file came out as above.
-
- 2. Note the LF/CR positioning between output from the two languages -
- Fortran/C has no included LF/CR
- Fortran/Fortran is OK, as is C/C
- but C/Fortran has two
-
- This might suggest that PRINT * sends a preceding LF/CR but no succeeding,
- whilst printf() does the reverse (??)
-
- ==============================================================================
-
- --
- +-------------------------------------------------------------------+
- | Dave Whatmuff | Voice: +1 612 482 4974 |
- | Control Data Systems, Inc. | |
- | Mail Station: ARH236 | FAX: +1 612 482 4985 |
- | 4201 Lexington Avenue North | |
- | Arden Hills, MN 55126 USA | Internet: whatmuff@cdc.com |
- +-------------------------------------------------------------------+
-